package com.hex.ds.hdtp.core.app.script.test.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.hex.ds.hdtp.core.app.common.enums.BasicTaskStatus;
import com.hex.ds.hdtp.core.app.common.page.PageData;
import com.hex.ds.hdtp.core.app.common.page.converter.IPageAndPageDtoConverter;
import com.hex.ds.hdtp.core.app.common.page.dto.PageDto;
import com.hex.ds.hdtp.core.app.script.test.converter.IScriptDataTestResultConverter;
import com.hex.ds.hdtp.core.app.script.test.converter.IScriptDataTestTaskConverter;
import com.hex.ds.hdtp.core.app.script.test.dto.request.ScriptDataTestListRequestDto;
import com.hex.ds.hdtp.core.app.script.test.dto.request.ScriptDataTestResultRequestDto;
import com.hex.ds.hdtp.core.app.script.test.dto.request.ScriptDataTestTaskRequestDto;
import com.hex.ds.hdtp.core.app.script.test.dto.response.ScriptDataTestListResponseDto;
import com.hex.ds.hdtp.core.app.script.test.dto.response.ScriptDataTestResultResponseDto;
import com.hex.ds.hdtp.core.app.script.test.dto.response.ScriptDataTestTaskResponseDto;
import com.hex.ds.hdtp.core.app.script.test.handler.IScriptDataTestHandlerService;
import com.hex.ds.hdtp.core.app.script.test.service.IScriptDataTestListService;
import com.hex.ds.hdtp.core.app.script.test.service.IScriptDataTestResultService;
import com.hex.ds.hdtp.core.app.script.test.service.IScriptDataTestTaskService;
import com.hex.ds.hdtp.core.app.script.transfer.dto.response.ScriptConvertTargetListResponseDto;
import com.hex.ds.hdtp.core.app.script.transfer.service.IScriptConvertSourceListService;
import com.hex.ds.hdtp.core.app.script.transfer.service.IScriptConvertTargetListService;
import com.hex.ds.hdtp.core.inf.common.exception.SourceSystemException;
import com.hex.ds.hdtp.core.inf.common.page.Page;
import com.hex.ds.hdtp.core.inf.script.test.po.ScriptDataTestTaskPo;
import com.hex.ds.hdtp.core.inf.script.test.repository.IScriptDataTestTaskRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

/**
 * @Package: com.hex.ds.hdtp.core.app.script.test.service.impl
 * @ClassName ScriptDataTestTaskService
 * @Description: 带数据测试任务-业务接口实现
 * @Author: wz.li
 * @Date 2023/8/1 16:23
 * @Version v2.0.2
 **/
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class ScriptDataTestTaskService implements IScriptDataTestTaskService {

    private final IScriptDataTestTaskRepository scriptDataTestTaskRepository;

    private final IScriptDataTestTaskConverter converter;

    private final IPageAndPageDtoConverter pageAndPageDtoConverter;

    private final IScriptDataTestResultConverter scriptDataTestResultConverter;

    private final IScriptDataTestResultService scriptDataTestResultService;

    private final IScriptDataTestListService scriptDataTestListService;

    private final IScriptDataTestHandlerService scriptDataTestHandlerService;

    private final IScriptConvertSourceListService scriptConvertListService;

    private final IScriptConvertTargetListService scriptConvertTargetListService;

    /*
     * @Method: queryListByPage <br>
     * @Param: [scriptDataTestTaskRequestDto, pageDto] <br>
     * @Return: com.hex.ds.hdtp.core.app.common.page.PageData <br>
     * @Description：分页查询<br>
     * @Author： wz.li<br>
     * @Date： 2023/8/1 16:30 <br>
     * @Version： V2.0.2<br>
     */
    @Override
    public PageData queryListByPage(ScriptDataTestTaskRequestDto scriptDataTestTaskRequestDto, PageDto pageDto) {
        final Page<ScriptDataTestTaskPo> pageResult = scriptDataTestTaskRepository.queryListByPage(
                converter.toScriptDataTestTaskPo(scriptDataTestTaskRequestDto), pageAndPageDtoConverter.toPage(pageDto));
        List<ScriptDataTestTaskResponseDto> responseDtos = converter.toScriptDataTestTaskResponseDtoList(pageResult.getData());
        return new PageData(responseDtos, pageResult.getTotal());
    }

    /*
     * @Method: queryList <br>
     * @Param: [scriptDataTestTaskRequestDto] <br>
     * @Return: java.util.List<com.hex.ds.hdtp.core.app.script.test.dto.response.ScriptDataTestTaskResponseDto> <br>
     * @Description：不分页查询<br>
     * @Author： wz.li<br>
     * @Date： 2023/8/1 16:30 <br>
     * @Version： V2.0.2<br>
     */
    @Override
    public List<ScriptDataTestTaskResponseDto> queryList(ScriptDataTestTaskRequestDto scriptDataTestTaskRequestDto) {
        final List<ScriptDataTestTaskPo> scriptDataTestTaskPos = scriptDataTestTaskRepository.queryList(converter.toScriptDataTestTaskPo(scriptDataTestTaskRequestDto));
        return converter.toScriptDataTestTaskResponseDtoList(scriptDataTestTaskPos);
    }

    /*
     * @Method: createTestTask <br>
     * @Param: [scriptDataTestTaskRequestDto] <br>
     * @Return: java.lang.String <br>
     * @Description：创建测试任务<br>
     * @Author： wz.li<br>
     * @Date： 2023/8/3 11:30 <br>
     * @Version： V2.0.2<br>
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public String createTestTask(ScriptDataTestTaskRequestDto scriptDataTestTaskRequestDto) {
        final ScriptDataTestTaskPo scriptDataTestTaskPo = converter.toScriptDataTestTaskPo(scriptDataTestTaskRequestDto);
        if (scriptDataTestTaskRepository.add(scriptDataTestTaskPo) != 1) {
            throw new RuntimeException("脚本测试任务-新增失败");
        }
        addScriptDataTestList(scriptDataTestTaskRequestDto.getTestScriptList(), scriptDataTestTaskPo.getPkId());
        return scriptDataTestTaskPo.getPkId();
    }

    /*
     * @Method: add <br>
     * @Param: [scriptDataTestTaskRequestDto] <br>
     * @Return: void <br>
     * @Description：新增<br>
     * @Author： wz.li<br>
     * @Date： 2023/8/1 16:30 <br>
     * @Version： V2.0.2<br>
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void add(ScriptDataTestTaskRequestDto scriptDataTestTaskRequestDto) {
        final ScriptDataTestTaskPo scriptDataTestTaskPo = converter.toScriptDataTestTaskPo(scriptDataTestTaskRequestDto);
        if (scriptDataTestTaskRepository.add(scriptDataTestTaskPo) != 1) {
            throw new SourceSystemException("脚本测试任务-新增失败");
        }
        addScriptDataTestList(scriptDataTestTaskRequestDto.getTestScriptList(), scriptDataTestTaskPo.getPkId());
    }

    /*
     * @Method: addScriptDataTestList <br>
     * @Param: [testScriptList, testTaskPkId] <br>
     * @Return: void <br>
     * @Description：新增带数据测试清单<br>
     * @Author： wz.li<br>
     * @Date： 2023/8/2 14:46 <br>
     * @Version： V2.0.2<br>
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void addScriptDataTestList(List<ScriptDataTestListRequestDto> testScriptList, String testTaskPkId) {
        for (ScriptDataTestListRequestDto scriptDataTestListRequestDto : testScriptList) {
            scriptDataTestListRequestDto.setTaskPkId(testTaskPkId);
            scriptDataTestListService.add(scriptDataTestListRequestDto);
        }
    }

    /*
     * @Method: modifyById <br>
     * @Param: [scriptDataTestTaskRequestDto] <br>
     * @Return: void <br>
     * @Description：根据主键更新<br>
     * @Author： wz.li<br>
     * @Date： 2023/8/1 16:30 <br>
     * @Version： V2.0.2<br>
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void modifyById(ScriptDataTestTaskRequestDto scriptDataTestTaskRequestDto) {
        final List<ScriptDataTestListResponseDto> scriptDataTestListResponseDtos =
                scriptDataTestListService.queryListByTaskId(scriptDataTestTaskRequestDto.getPkId());
        deleteTestScript(scriptDataTestListResponseDtos, scriptDataTestTaskRequestDto);
        addTestScript(scriptDataTestListResponseDtos, scriptDataTestTaskRequestDto);
        updateById(scriptDataTestTaskRequestDto);
    }

    /*
     * @Method: deleteTestScript <br>
     * @Param: [scriptDataTestListResponseDtos, scriptDataTestTaskRequestDto] <br>
     * @Return: void <br>
     * @Description：删除不要测试的测试脚本<br>
     * @Author： wz.li<br>
     * @Date： 2023/8/4 11:54 <br>
     * @Version： V2.0.2<br>
     */
    private void deleteTestScript(List<ScriptDataTestListResponseDto> scriptDataTestListResponseDtos,
                                  ScriptDataTestTaskRequestDto scriptDataTestTaskRequestDto) {
        List<String> scriptPkIds = scriptDataTestTaskRequestDto.getTestScriptList()
                .stream().map(ScriptDataTestListRequestDto::getScriptConvertListPkId).collect(Collectors.toList());
        for (ScriptDataTestListResponseDto scriptDataTestListResponseDto : scriptDataTestListResponseDtos) {
            if (!scriptPkIds.contains(scriptDataTestListResponseDto.getScriptConvertListPkId())) {
                scriptDataTestListService.removeById(scriptDataTestListResponseDto.getPkId());
            }
        }
    }

    /*
     * @Method: addTestScript <br>
     * @Param: [scriptDataTestListResponseDtos, scriptDataTestTaskRequestDto] <br>
     * @Return: void <br>
     * @Description：新增新添加的测试脚本<br>
     * @Author： wz.li<br>
     * @Date： 2023/8/4 11:54 <br>
     * @Version： V2.0.2<br>
     */
    private void addTestScript(List<ScriptDataTestListResponseDto> scriptDataTestListResponseDtos,
                               ScriptDataTestTaskRequestDto scriptDataTestTaskRequestDto) {
        List<String> scriptPkIds = scriptDataTestListResponseDtos.stream().map(ScriptDataTestListResponseDto::getScriptConvertListPkId).collect(Collectors.toList());
        for (ScriptDataTestListRequestDto scriptDataTestListRequestDto : scriptDataTestTaskRequestDto.getTestScriptList()) {
            if (!scriptPkIds.contains(scriptDataTestListRequestDto.getScriptConvertListPkId())) {
                scriptDataTestListRequestDto.setTaskPkId(scriptDataTestTaskRequestDto.getPkId());
                scriptDataTestListService.add(scriptDataTestListRequestDto);
            }
        }
    }

    /*
     * @Method: updateById <br>
     * @Param: [scriptDataTestTaskRequestDto] <br>
     * @Return: void <br>
     * @Description：根据主键更新测试任务<br>
     * @Author： wz.li<br>
     * @Date： 2023/8/4 11:40 <br>
     * @Version： V2.0.2<br>
     */
    private void updateById(ScriptDataTestTaskRequestDto scriptDataTestTaskRequestDto) {
        int count = scriptDataTestTaskRepository.modifyById(converter.toScriptDataTestTaskPo(scriptDataTestTaskRequestDto));
        if (count != 1) {
            throw new RuntimeException("脚本测试任务-修改失败");
        }
    }

    /*
     * @Method: removeById <br>
     * @Param: [pkId] <br>
     * @Return: void <br>
     * @Description：根据主键删除<br>
     * @Author： wz.li<br>
     * @Date： 2023/8/1 16:30 <br>
     * @Version： V2.0.2<br>
     */
    @Override
    public void removeById(String pkId) {
        int count = scriptDataTestTaskRepository.removeById(pkId);
        if (count != 1) {
            throw new RuntimeException("脚本测试任务-删除失败");
        }
    }

    /*
     * @Method: modifySuccessById <br>
     * @Param: [pkId] <br>
     * @Return: void <br>
     * @Description：根据测试任务主键更新任务测试成功个数<br>
     * @Author： wz.li<br>
     * @Date： 2023/8/7 18:18 <br>
     * @Version： V2.0.2<br>
     */
    @Override
    public void modifySuccessById(String pkId) {
        scriptDataTestTaskRepository.modifySuccessById(pkId);
    }

    /*
     * @Method: modifyFailNumById <br>
     * @Param: [pkId] <br>
     * @Return: void <br>
     * @Description：根据测试任务主键更新任务测试失败个数<br>
     * @Author： wz.li<br>
     * @Date： 2023/8/7 18:18 <br>
     * @Version： V2.0.2<br>
     */
    @Override
    public void modifyFailNumById(String pkId) {
        scriptDataTestTaskRepository.modifyFailNumById(pkId);
    }

    /*
     * @Method: batchRemoveById <br>
     * @Param: [pkIds] <br>
     * @Return: void <br>
     * @Description：根据主键批量删除<br>
     * @Author： wz.li<br>
     * @Date： 2023/8/1 16:30 <br>
     * @Version： V2.0.2<br>
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void batchRemoveById(List<String> pkIds) {
        for (String pkId : pkIds) {
            removeById(pkId);
        }
    }

    /**
     * @Method queryById <br>
     * @Param
     * @Param pkId <br>
     * @Return com.hex.ds.hdtp.core.app.script.test.dto.response.ScriptDataTestTaskResponseDto <br>
     * @Description 根据id查询<br>
     * @Author jian.qiao<br>
     * @Date 2023/10/27 18:39 <br>
     * @Version V1.0<br>
     */
    @Override
    public ScriptDataTestTaskResponseDto queryById(String pkId) {
        return converter.toScriptDataTestTaskResponseDto(scriptDataTestTaskRepository.queryById(pkId));
    }

    /*
     * @Method: test <br>
     * @Param: [pkId] <br>
     * @Return: void <br>
     * @Description：带数据测试任务-测试<br>
     * @Author： wz.li<br>
     * @Date： 2023/8/4 17:39 <br>
     * @Version： V2.0.2<br>
     */
    @Override
    public void test(String pkId) {
        try {
            // 初始化信息
            scriptDataTestTaskRepository.modifyById(converter.toScriptDataTestTaskPo(new ScriptDataTestTaskRequestDto()
                    .setPkId(pkId).setStartTime(DateUtil.format(new DateTime(), "yyyy-MM-dd HH:mm:ss"))
                    .setTestSuccessCount(0).setTestFailCount(0)));
            ScriptDataTestTaskPo scriptDataTestTaskPo = scriptDataTestTaskRepository.queryById(pkId);
            String batchCode = createScriptTestExample(scriptDataTestTaskPo);
            List<ScriptDataTestResultResponseDto> scriptDataTestResultList = scriptDataTestResultService.queryList(batchCode, pkId);
            updateTaskStatus(pkId, BasicTaskStatus.PROCESSING.name(), scriptDataTestResultList.size());
            for (ScriptDataTestResultResponseDto scriptDataTestResult : scriptDataTestResultList) {
                scriptDataTestHandlerService.test(scriptDataTestTaskPo, scriptDataTestResult);
            }
            updateTaskStatus(pkId, BasicTaskStatus.FINISH.name(), null);
        } catch (Exception e) {
            log.error("脚本带数据测试失败：{}", e.getMessage(), e);
            updateTaskStatus(pkId, BasicTaskStatus.FAIL.name(), null);
            throw new RuntimeException("脚本带数据测试失败:" + e.getMessage());
        }
    }

    /*
     * @Method: dataAlignment <br>
     * @Param: [pkId] <br>
     * @Return: void <br>
     * @Description：数据分析<br>
     * @Author： wz.li<br>
     * @Date： 2023/8/8 10:30 <br>
     * @Version： V2.0.2<br>
     */
    @Override
    public void dataAlignment(String pkId) {
        ScriptDataTestTaskPo scriptDataTestTaskPo = scriptDataTestTaskRepository.queryById(pkId);
        scriptDataTestHandlerService.dataAlignment(scriptDataTestTaskPo);
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public String createScriptTestExample(ScriptDataTestTaskPo scriptDataTestTaskPo) {
        String batchCode = DateUtil.format(DateUtil.date(), "yyyyMMddHHmmss");
        List<ScriptDataTestListResponseDto> scriptDataTestList = scriptDataTestListService.queryListByTaskId(scriptDataTestTaskPo.getPkId());
        for (ScriptDataTestListResponseDto scriptDataTestListResponseDto : scriptDataTestList) {
            ScriptConvertTargetListResponseDto scriptConvertList = scriptConvertTargetListService.queryById(scriptDataTestListResponseDto.getScriptConvertListPkId());
            for (DateTime dateTime : scriptDataTestTaskPo.getBizDateList()) {
                ScriptDataTestResultRequestDto scriptDataTestResultRequestDto = scriptDataTestResultConverter
                        .toScriptDataTestResultRequestDto(
                                scriptDataTestListResponseDto,
                                batchCode,
                                DateUtil.format(dateTime, "yyyyMMdd"),
                                scriptConvertList.getConvertFilePath()
                        );
                scriptDataTestResultService.add(scriptDataTestResultRequestDto);
            }
        }
        return batchCode;
    }

    /*
     * @Method: updateTaskStatus <br>
     * @Param: [pkId, status] <br>
     * @Return: void <br>
     * @Description：更新测试任务状态<br>
     * @Author： wz.li<br>
     * @Date： 2023/8/4 17:56 <br>
     * @Version： V2.0.2<br>
     */
    private void updateTaskStatus(String pkId, String status, Integer scriptTestTotal) {
        ScriptDataTestTaskPo scriptDataTestTaskPo = new ScriptDataTestTaskPo().setPkId(pkId).setStatus(status);
        if (status.equals(BasicTaskStatus.PROCESSING.name())) {
            scriptDataTestTaskPo.setStartTime(DateUtil.now());
            scriptDataTestTaskPo.setTestTotal(scriptTestTotal);
        } else {
            scriptDataTestTaskPo.setEndTime(DateUtil.now());
        }
        scriptDataTestTaskRepository.modifyById(scriptDataTestTaskPo);
    }
}
